package mskruch.gps;


import java.io.Serializable;

import mskruch.gps.util.PointsUtil;

/**
 * GPS Track (immutable)
 * 
 * @author Marcin Skruch
 * 
 */
public class Track implements Serializable {
    private static final long serialVersionUID = 1L;

    private final String name;
    private final Lap[] laps;
    
    // additional data
	private Float totalDistance;
	private Integer totalAscent;
	private Integer totalDescent;
    private Short avgCadence;
    private Short avgHeartRate;
    private Float avgSpeed;
    private Float totalElapsedTime;
    private Float totalTimerTime;
    
    
    private transient Point[] points; /* cache */

    
    
	
	public Track(String name, Lap[] laps, Float totalDistance, Integer totalAscent, Integer totalDescent, Short avgCadence, Short avgHeartRate, Float avgSpeed,
			Float totalElapsedTime, Float totalTimerTime) {
        super();
        if (laps == null || laps.length == 0) {
            throw new IllegalArgumentException("a track must have at least one lap");
        }
        this.name = name;
        this.laps = laps;
		this.totalDistance = totalDistance;
		this.totalAscent = totalAscent;
		this.totalAscent = totalAscent;
		this.avgCadence = avgCadence;
		this.avgHeartRate = avgHeartRate;
		this.avgSpeed = avgSpeed;
		this.totalElapsedTime = totalElapsedTime;
		this.totalTimerTime = totalTimerTime;
    }
    
    public Track(String name, Lap[] laps) {
        this (name, laps, null, null, null, null, null, null, null, null);
    }
    
    public Track(String name, Point[] points){
        this(name, new Lap(points));
    }
    
    public Track(String name, Lap lap) {
        this(name, new Lap[] { lap });
    }

    public String getName() {
        return name;
    }

    public Lap[] getLaps() {
        return laps;
    }

    /**
     * Get track points from all laps
     * 
     * @return all track points
     */
    public Point[] getPoints() {
        if (points == null) {
            if (laps.length == 1) {
                return laps[0].getPoints();
            } else if (laps.length == 0) {
                return new Point[0];
            } else {
                int count = 0;
                for (Lap lap : laps) {
                    count += lap.getPoints().length;
                }
                points = new Point[count];
                int index = 0;
                for (Lap lap : laps) {
                    for (Point point : lap.getPoints()) {
                        points[index++] = point;
                    }
                }
            }
        }
        return points;
    }

    public Integer getTotalAscent() {
		return totalAscent;
	}

    public Float getTotalDistance() {
		return totalDistance;
	}

	public Integer getTotalDescent() {
		return totalDescent;
	}
    
	public Short getAvgCadence() {
		return avgCadence;
	}

	public Short getAvgHeartRate() {
		return avgHeartRate;
	}

	public Float getAvgSpeed() {
		return avgSpeed;
	}

	public Float getTotalElapsedTime() {
		return totalElapsedTime;
	}

	public Float getTotalTimerTime() {
		return totalTimerTime;
	}
    
    
    public Point calculatePointByDistance(double distance) {
        Point[] points = getPoints();
        return PointsUtil.calculatePointByDistance(points, distance);
    }

}
